package com.pms.init.manager;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ClassUtils;

import com.espirit.eap.manager.I18n;
import com.espirit.eap.manager.I18nData;
import com.espirit.eap.manager.ModelBuilder;
import com.espirit.eap.manager.ModelDirector;
import com.espirit.eap.pagelayout.ElementService;
import com.espirit.eap.pagelayout.LayoutService;
import com.googlecode.cswish.annotation.Dependence;
import com.googlecode.cswish.struts.hibernate.DynamicModelManager;
import com.googlecode.cswish.struts.hibernate.HibernateConfiguration;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ObjectFactory;


/**
 * Manage DataBase
 * 	 
 * @author jerry.feng Date: 2008-10-24
 */
public abstract class DBAService {
	
	@Resource
	private HibernateConfiguration hibernateConfiguration;

	@Resource
	ObjectFactory factory; 

	@Resource
	LayoutService layoutService;
	
	@Resource
	GenericService genericService;
	
	@Resource
	ElementService elementService;

	@Resource
	ObjectFactory objectFactory;
	
	@Resource
	private DynamicModelManager dynamicModelManager;
	
	
//	@Resource
//	BaseTypeModelManager baseTypeModelManager;

	private static final Log logger = LogFactory.getLog(DBAService.class);
	
	public boolean init() {
		initDB("create-drop");
		initModel();
		initModelInitData();
		initI18nData();
		initSystemData();
		return true;
	}
	
	public void builderModel(String packageName) {
		System.out.println("init package :" + packageName);
		List<ModelBuilder> builders = getBuilders(packageName);
		Set<String> done = new HashSet<String>();
		int beginSize = 0;			// for the debug facility
		int totalSize = builders.size();
		DBAService self = objectFactory.getBean(this.getClass(), false);
		for(ModelBuilder builder : builders){
			self.buildModel(builder, done, beginSize, totalSize);
		}
		
		for(ModelBuilder builder : builders){
			self.builderMiscData(builder);
		}
	}
	
	@Transactional
	public void buildModel(ModelBuilder builder, Set<String> done, int beginSize, int totalSize) {
		if (done.contains(builder.getClass().getName())) {
			return;
		}
		
		List<Dependence> dependences = null;
		Class clazz = builder.getClass();
		while (clazz != null) {
			Dependence dependence = (Dependence) clazz.getAnnotation(Dependence.class);
			if (dependence != null) {
				if (dependences == null) {
					dependences = new ArrayList<Dependence>();
				}
				dependences.add(dependence);
			}
			clazz = clazz.getSuperclass();
		}
		
		if (dependences != null) {
			for (Dependence dependence : dependences) {
				for (String builderName : dependence.value()) {
					if (!done.contains(builderName)) {
						ModelBuilder builderDependence = (ModelBuilder) objectFactory.getBean(builderName, true);
						buildModel(builderDependence, done, beginSize, totalSize);
					}
				}
			}
		}
		
		if (logger.isDebugEnabled()) {
			logger.debug(done.size() + "/" + totalSize + ", build :"+ builder.getClass().getName());
		}
		
		if (done.size() >= beginSize) {
			builderModelFieldsProperty(builder);
	
			builderModleFieldsInfo(builder);
	
			builderModelFields(builder);
	
			builderLayout(builder);
	
			builder.preBuildMiscData();
			
			builder.clean();
		}
		
		done.add(builder.getClass().getName());
	}
	
	public void upradeModel(String builderName) {
		ModelBuilder builder = (ModelBuilder) factory.getBean(builderName, false);
		DBAService self = objectFactory.getBean(this.getClass(), false);
		
		Set<String> done = new HashSet<String>();
		self.buildModel(builder, done, 0, 1);
		
		self.builderMiscData(builder);
	}
	
	private void builderModelFieldsProperty(ModelBuilder builder) {
		ModelDirector director = new ModelDirector(builder);
		director.contruct();
		builder.getResult();
	}
	private void builderModelFields(ModelBuilder builder) {
		ModelDirector director = new ModelDirector(builder);
		director.buildFields();
//		director.contruct();
//		builder.getResult();
	}
	private void builderModleFieldsInfo(ModelBuilder builder){
		ModelDirector director = new ModelDirector(builder);
		director.buildFieldsInfo();
	}
	
	private void builderLayout(ModelBuilder builder){
		ModelDirector director = new ModelDirector(builder);
		director.buildLayout();
	}
	
	@Transactional
	public void builderMiscData(ModelBuilder builder){
		ModelDirector director = new ModelDirector(builder);
		director.buildMiscData();
		
		builder.clean();
	}
	
	protected void builderModelInitData(ModelBuilder builder){
		ModelDirector director = new ModelDirector(builder);
		director.buildModelInitData();
	}
	
	protected void builderModelInitData(String packageName){
		List<ModelBuilder> builders = getBuilders(packageName);
		for(ModelBuilder builder : builders){
			builderModelInitData(builder);
		}
	}
	public void initDB(String initModel){
		hibernateConfiguration.getConfigurations().get(0).setProperty("cswish.hbm2ddl.auto", initModel);
		dynamicModelManager.refreshDbSchema();
	}
	
	/*
	 * 清除页面元素数据
	 */
	public void cleanElementData(){
	}
	
	protected int executeSql(String hql){
		return elementService.getSession().createSQLQuery(hql).executeUpdate();
	}

	public void initModel(){
		cleanElementData();
	}
	
	protected void saveI18nData(I18nData data){
		int itemCount = 0;
		for(I18n resource : data.getData()){
			I18n model = new I18n();
			model.setKey(resource.getKey());
			model = genericService.searchAll(model).getData(0);
			if (model == null ){
				genericService.add(resource);
			}
			if (++itemCount % 100 == 0){
			}
		}
		data.getData().clear();
	}
	protected abstract void initModelInitData();
	public abstract void initI18nData();
	public abstract  void initSystemData();
	
	
	public List<ModelBuilder> getBuilders(String packageName){
//		if (builders == null) {
		    List<ModelBuilder> builders = new ArrayList<ModelBuilder>();
			try {
				ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
				String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + 
						ClassUtils.convertClassNameToResourcePath(packageName) + "/**/*Builder.class";
				org.springframework.core.io.Resource[] resources = resolver.getResources(pattern);  
				for (org.springframework.core.io.Resource resource : resources) {
					try{
						String filename = resource.getFilename();
						String beanName = packageName + "." + filename.substring(0, filename.length() - 6);		// skip .class
						Object obj = factory.getBean(beanName, false);
						if (obj instanceof ModelBuilder){
							ModelBuilder builder = (ModelBuilder)obj;
							builders.add(builder);
							
						}
					} catch (Exception ex){
						logger.debug(ex);
					}
				}
				
			} catch (IOException ex) {
				logger.error("Read Builder", ex);
			}
//		} 
		return builders;
	}
}
